import type { Ref } from "vue";
import { ref, reactive, watch } from "vue";
import { debounceAsync } from "zf-utilz";

type PagePagingStateRaw<T, F extends Record<string, any>> = {
  filter: F;
  currentPage: number;
  pageSize: number;
  startIndex: number;
  records: Ref<T[]>;
  total: number;
  loading: boolean;
  finished: boolean;
  emptyed: boolean;
  selection: Ref<T[]>;
  load: (page?: number, filter?: Partial<F>) => Promise<void>;
  refresh: () => Promise<void>;
  reset: () => Promise<void>;
  handleCurrentPageChange: (page?: number) => void;
  handlePageSizeChange: (size?: number) => void;
  handleFilterChange: (filter?: Partial<F>) => void;

  rowView: (row: T) => Promise<void>;
  rowEdit: (row: T) => Promise<void>;
  rowDelete: (row: T) => Promise<void>;
  rowDisable: (row: T) => Promise<void>;
  rowEnable: (row: T) => Promise<void>;
};

type PagePagingParams<T, F extends Record<string, any>> = {
  filter?: F;
  watchFilter?: boolean;
  pageSize?: number;
  getRecords(
    page: number,
    size: number,
    filter: F
  ): Promise<{ records?: T[]; list?: T[]; total: number }>;
  handleRowView?: (row: T) => Promise<void>;
  handleRowEdit?: (row: T) => Promise<void>;
  handleRowDelete?: (row: T) => Promise<void>;
  handleRowDisable?: (row: T) => Promise<void>;
  handleRowEnable?: (row: T) => Promise<void>;
};

export const useListPaging = function <
  T,
  F extends Record<string, any> = Record<string, any>
>(params: PagePagingParams<T, F>) {
  const defaultFilter = ref<F>(JSON.parse(JSON.stringify(params.filter ?? {})));

  const state = reactive<PagePagingStateRaw<T, F>>({
    filter: params.filter ?? ({} as F),
    startIndex: 0,
    currentPage: 1,
    pageSize: params.pageSize ?? 10,
    records: ref<T[]>([]) as Ref<T[]>,
    total: 0,
    loading: false,
    finished: false,
    emptyed: false,
    selection: ref<T[]>([]) as Ref<T[]>,

    // 跳转
    async load(page, filter) {
      await refreshByPage(page ?? state.currentPage, state.pageSize, filter);
    },

    // 刷新
    async refresh() {
      await refreshByPage(state.currentPage, state.pageSize);
      state.selection = [];
    },

    // 重置
    async reset() {
      await refreshByPage(1, state.pageSize, defaultFilter.value);
      state.selection = [];
    },

    // 监听当前页更新事件
    handleCurrentPageChange(page) {
      refreshByPage(page ?? state.currentPage, state.pageSize);
    },

    // 监听每页条数更新事件
    handlePageSizeChange(size) {
      refreshByPage(1, size ?? state.pageSize);
    },

    // 监听条件查询
    handleFilterChange(filter) {
      refreshByPage(1, state.pageSize, filter);
    },

    // 查看详情
    async rowView(row) {
      try {
        await params.handleRowView?.(row);
      } catch (error) {
        if (error === "cancel") return;
        console.error(error);
      }
    },
    // 编辑
    async rowEdit(row) {
      try {
        await params.handleRowEdit?.(row);
      } catch (error) {
        if (error === "cancel") return;
        console.error(error);
      }
    },

    // 删除
    async rowDelete(row) {
      try {
        await params.handleRowDelete?.(row);
      } catch (error) {
        if (error === "cancel") return;
        console.error(error);
      }
    },

    // 禁用
    async rowDisable(row) {
      try {
        await params.handleRowDisable?.(row);
      } catch (error) {
        if (error === "cancel") return;
        console.error(error);
      }
    },

    // 启用
    async rowEnable(row) {
      try {
        await params.handleRowEnable?.(row);
      } catch (error) {
        if (error === "cancel") return;
        console.error(error);
      }
    }
  });

  // 请求ID
  const requestId = ref(0);

  // 获取数据
  const refreshByPage = async function (
    page: number,
    size: number,
    filter?: Partial<F>
  ) {
    if (state.loading) return;

    state.loading = true;
    try {
      Object.assign(state.filter as F, filter);

      const _requestId = (requestId.value += 1);
      const { records, list, total } = await params.getRecords(
        page,
        size,
        state.filter as F
      );
      if (_requestId !== requestId.value) return;

      state.records = records ?? list ?? [];
      state.total = total;
      state.currentPage = page;
      state.pageSize = size;
      state.startIndex = (page - 1) * size + 1;
      state.emptyed = total <= 0;
      state.finished = state.currentPage * state.pageSize >= state.total;
    } catch (error) {
      state.loading = false;
      console.error(error);
      throw error;
    }
    state.loading = false;
  };

  if (params.watchFilter) {
    watch(
      () => JSON.stringify(state.filter),
      debounceAsync(async () => {
        return refreshByPage(1, state.pageSize);
      }, 200)
    );
  }

  return state;
};

export default useListPaging;
